/* Copyright (C) 2008  Romolo Camplani, Marco Fortunato, Marco Marelli, Guido Rota, Fabio A. Schreiber et al.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.dei.perla.utils.logger;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;


/**
 * Logger su database SQLite: inserisce in una tabella di SqLite i messaggi ricevuti
 */
public class SqLiteLogger extends Logger {		
	
	/**
	 * Path del file SqlLite
	 */
	private String pDbFile;
	
	/**
	 * Nome della tabella di log
	 */
	private String pDbTable;
	
	/**
	* Connessione al database SqLite
	*/
	private Connection pDbConnection;
	 
	
	/**
	 * Costruttore 
	 * @param parDbFile Path del file SqLite
	 * @param parTableName Nome della tabella in cui salvare il log
	 */
	public SqLiteLogger(String parDbFile, String parDbTable) {
		
		// Memorizza le impostazioni
		this.pDbFile = parDbFile;
		this.pDbTable = parDbTable;
		this.pDbConnection = null;
	}
	
	
	/**
	 * Inizializza il Logger, aprendo il database (o creandolo se non esiste)
	 */
	protected boolean logStart() {
		
		boolean tOk              = true;
		boolean tCreateTable     = false;
		String tConnectionString = "";
		String tSql              = ""; 
		
			
		// Prova a caricare il driver JDBC per SqLite
		if(tOk) {			
			try {				
				Class.forName("org.sqlite.JDBC");
			}
			catch(Exception parException) { 
				this.setErrorMessage("Impossibile trovare il driver JDBC pere SQLite.");
				tOk = false;
			}
		}
		
		// Prova ad aprire il database
		if(tOk) {
			try {
				tConnectionString = "jdbc:sqlite:" + this.pDbFile;
				this.pDbConnection = DriverManager.getConnection(tConnectionString);
			}
			catch(Exception parException) {
				this.setErrorMessage("Impossibile aprire/creare il database SQLite: " + this.pDbFile);
				tOk = false;
			}
		}
		
		// Determina se la tabella di log esiste già nel database
		if(tOk) {
			tSql = "SELECT * FROM " + this.pDbTable;
			tCreateTable = !this.pExecuteSql(tSql, false);
		}
		
		// Se la tabella di log non esiste, prova a crearla
		if(tOk && tCreateTable) {
			tSql = "CREATE TABLE " + this.pDbTable + "(Time DATETIME, SourceType NVARCHAR(255), SourceName NVARCHAR(255), MessageType NVARCHAR(1), Message NVARCHAR(255), Details NVARCHAR(255))";
			if(!this.pExecuteSql(tSql, true)) {
				this.setErrorMessage("Impossibile creare la tabella di log (" + this.pDbTable + ")");
				tOk = false;
			}
		}
		
		return tOk;
	}
	
	
	/**
	 * Termina il Logger chiudendo la connessione al database;
	 */
	protected void logStop() {
		
		if(this.pDbConnection != null) {
			try {
				this.pDbConnection.close();
			}
			catch(Exception parException) { }
			this.pDbConnection = null;
		}
	}
	
	
	/**
	 * Aggiunge un record di log speciale 
	 */
	protected void logReset() {
			
	}
	
	
	/**
	 * Aggiunge un record alla tabella di log
	 */
	protected boolean logAdd(LogRecord parLogRecord) {
		
		String tSql;
		String tMessageTypeCode = "";
		String tTime = "";
		
		// Determina il codice associato  al tipo di messaggio
		if     (parLogRecord.getMessageType() == LogRecord.Type.Information) tMessageTypeCode = "I";
		else if(parLogRecord.getMessageType() == LogRecord.Type.Warning)     tMessageTypeCode = "W";
		else if(parLogRecord.getMessageType() == LogRecord.Type.Error)       tMessageTypeCode = "E";		
		
		// Costruisce la stringa 
		tTime = (new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm:ss")).format(parLogRecord.getTime());
		
		// Costruisce la stringa SQL di inserimento
		tSql = "INSERT INTO " + this.pDbTable + "(Time, SourceType, SourceName, MessageType, Message, Details) VALUES (";
		tSql += "datetime('" + tTime + "'), ";
		tSql += this.pStringaSqlValida(parLogRecord.getSourceType()) + ", ";
		tSql += this.pStringaSqlValida(parLogRecord.getSourceName()) + ", ";
		tSql += this.pStringaSqlValida(tMessageTypeCode) + ", ";
		tSql += this.pStringaSqlValida(parLogRecord.getMessage()) + ", ";
		tSql += this.pStringaSqlValida(parLogRecord.getDetails());
		tSql += ")";
		
		// Esegue la query costruita
		return this.pExecuteSql(tSql, true);
	}
	

	/**
	 * Trasforma la stringa passata per parametro in una stringa SQL valida (raddoppiando gli apici)
	 */
	private String pStringaSqlValida(String parSql) {
	
		if((parSql != null) && (!"".equals(parSql))) 
			return "'" + parSql.replace("'", "''") + "'";
		else
			return "NULL";
	}
	
	
	/**
	 * Esegue lo statement SQL passato per parametro
	 * @return True se non si sono verificati errori
	 */
	private boolean pExecuteSql(String parSql, boolean parUpdate) {
		
		Statement tStatement = null;
		boolean tOk;
		
		
		// Verifica che la connessione al database sia aperta
		tOk = (this.pDbConnection != null);
		
		// Prova ad eseguire lo statement SQL
		if(tOk) {
			try {
				tStatement = this.pDbConnection.createStatement();
				if(parUpdate)
					tStatement.executeUpdate(parSql);
				else
					tStatement.execute(parSql);
			}
			catch (Exception parException) {
				tOk = false;
			}
		}
		
		// Dealloca l'oggetto Statement
		if(tStatement != null) {
			try {
				tStatement.close();
			}
			catch(Exception parException) { }
			tStatement = null;
		}
		
		// Restituisce True se l'SQL è stato eseguito senza errori
		return tOk;
	}
	
}